package org.esti.model.dao.impl;

import org.esti.model.Appraisal;
import org.esti.model.dao.AppraisalDAO;
import org.esti.model.exceptions.AppraisalCannotBeDefinedUniquelyException;
import org.esti.model.exceptions.AppraisalDoesNotExistException;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.*;
import java.util.List;

/**
 * @author Artem Loginov (logart)
 */
@Repository
public class AppraisalDAOimpl implements AppraisalDAO {

    @PersistenceContext
    private EntityManager entityManager;

    /**
     * {@inheritDoc}
     */
    @Transactional(readOnly = true)
    @Override
    public Appraisal getAppraisalByLevelId(long levelId) {
        try {
            Query query = entityManager.createQuery(
                    "SELECT a FROM Appraisal a WHERE a.level.id=:level_id AND a.publish=true"
            );
            query.setParameter("level_id", levelId);
            return (Appraisal) query.getSingleResult();
        } catch (NoResultException ex) {
            throw new AppraisalDoesNotExistException(ex);
        } catch (NonUniqueResultException ex) {
            throw new AppraisalCannotBeDefinedUniquelyException(ex);
        }
    }

    /**
     * {@inheritDoc}
     */
    @Transactional
    @Override
    public Appraisal add(Appraisal appraisal) {
        return entityManager.merge(appraisal);
    }

    /**
     * {@inheritDoc}
     */
    @Transactional(readOnly = true)
    @Override
    public List<Appraisal> getAllAppraisals() {
        return entityManager.createQuery("SELECT a FROM Appraisal a").getResultList();
    }

    /**
     * {@inheritDoc}
     */
    @Transactional(readOnly = true, noRollbackFor = {AppraisalDoesNotExistException.class})
    @Override
    public Appraisal getAppraisalById(long id) {
        Appraisal appraisal = entityManager.find(Appraisal.class, id);
        if (appraisal == null) {
            throw new AppraisalDoesNotExistException();
        } else {
            return appraisal;
        }
    }

    /**
     * {@inheritDoc}
     */
    @Transactional
    @Override
    public Appraisal update(Appraisal appraisal) {
        return entityManager.merge(appraisal);
    }

    /**
     * {@inheritDoc}
     */
    @Transactional
    @Override
    public void remove(long id) {
        Appraisal app = entityManager.find(Appraisal.class, id);
        entityManager.remove(app);
    }

    /**
     * {@inheritDoc}
     */
    @Transactional(readOnly = true)
    @Override
    public List<Appraisal> getAvailableAppraisals() {
        return (List<Appraisal>) entityManager.createQuery(
                "SELECT a FROM Appraisal a WHERE a.publish=true"
        ).getResultList();
    }
}
